---
slug: redux工程化 #路径，不能重复
title: redux工程化 # 标题
authors: [] # 作者，在authors.yml配置
tags: [facebook, hello, docusaurus] # 标签，在tags.yml配置
toc_min_heading_level: 2 # 最小展示标题
toc_max_heading_level: 5 # 最大展示标题
---
## reducer的拆分与合并
> `combineReducers`目的是合并各个模块的reducer,最后创建一个总的reducer

> dispatch时候会去**每个模块**的reducer中把**所有**和派发行为标识`type`匹配的都执行一遍

#### 先定义第一个模块的reducer

`src/store/reducer/PersonalReducer.js`

```js
const init = {
    num:0,
    up:0
}
export  default function personalReducer(state = init, action) {
    switch (action.type) {
        case "VOTE_UP":
            return {
                ...state,up:init.up+1
            }
    }
}
```
#### 定义第二个模块的reducer
`src/store/reducer/VoteReducer.js`

```js
const init = {
    num:0,
    up:0
}
export  default function VoteReducer(state = init, action) {
    switch (action.type) {
        case "VOTE_UP":
            return {
                ...state,up:init.up+1
            }
    }
}
```

#### 合并reducer
`src/store/reducer/index.js`
```js
import {combineReducers} from "redux";
import VoteReducer from "./VoteReducer";
import PersonalReducer from "./PersonalReducer";

export default
    combineReducers({
        vote:VoteReducer,
        personal:PersonalReducer,
    })
```

#### 注意：此时是reducer，还不是我们需要的store
`src/store/index.js`

##### 导入合并后的reducer
```js
import combinedReducers from './reducer';
const store = createStore(combinedReducers);

export default store;
```

#### 在需要store的地方使用store
1. 结构全局上下文取全局状态中要取在`combineReducers`中定义的reducer
2. 但是`subscribe`和`dispatch`不需要

```jsx
import React, {useContext,useEffect,useState} from 'react';
import {Button, Divider} from "antd";
import ThemeContext from "../../ThemeContext";
import * as  Types from '../../store/action-types';
export const ReduxStudy = function () {
    //解构出context
    const {store} = useContext(ThemeContext);
    const voteStore = store.getState().vote;
    const {up, down} = voteStore;

    //只是为了让组件更新
    const [_, setState] = useState(0)

    const updateState = ()=>{
        setState(prevState => prevState + 1);
    }

    useEffect(()=>{
        const unSubscribe =  store.subscribe(updateState);
         return () => unSubscribe();//必须需要这个清除函数
    },[])
    return (
        <>
            <div className={'container'}>
                <h2>React是很棒的框架</h2>
                <div>
                    {up+down}
                </div>
            </div>
            <div>
                <div>
                    赞同票数:{up}
                </div>
                <div>
                    反对票数:{down}
                </div>
            </div>
            <Divider/>
            <Button onClick={()=>store.dispatch({type:Types.VOTE_UP})}>
                投赞同票
            </Button>

            <Button onClick={()=>store.dispatch({type:Types.VOTE_DOWN})}>
                投反对票
            </Button>
        </>
    )

};
```

## 派发行为宏标识管理(就是定义一个全局文件而已)
> 因为`combineReducers`执行`dispatcher`时候会把所有和`type`一样的都执行一遍，所以我们要确保type的唯一性

### 问题引出

> vote中的type假设有一个为vote-up,personal中也有一个vote-up的，如果`dispatch({type:'vote-up'})`则两个都会执行

```js
const reducer =   combineReducers({
    vote:VoteReducer,
    personal:PersonalReducer,
})
```

### 解决(全局定义type宏管理)

`src/store/action-types.js`

```js

//派发行为宏标识管理

export const VOTE_UP = "vote-up";

export const VOTE_DOWN = "vote-down";


export const PERSONAL_DELETE = "personal-delete";

export const PERSONAL_UPDATE = "personal-update";

export const PERSONAL_ADD = "personal-add";
```
### 在对应需要`dispatch`的地方替换即可

> 假设是`ReduxStudy.jsx`,且假设已经在webpack配置`@`指向src,当然了,全局types宏文件可以随意定义位置
```jsx
import * as Types from '@/store/action-types';
//----中间略
store.dispatch({type:Types.VOTE_UP});
```

